# DatabaseCrudOperations.java

    package org.codefilarete.stalactite.engine.crud;

    import java.util.List;
    import java.util.Set;
    import java.util.function.Consumer;

    import org.codefilarete.stalactite.engine.ExecutableQuery;
    import org.codefilarete.stalactite.engine.PersistenceContext.ExecutableBeanPropertyKeyQueryMapper;
    import org.codefilarete.stalactite.engine.PersistenceContext.SelectMapping;
    import org.codefilarete.stalactite.engine.QueryMapper;
    import org.codefilarete.stalactite.query.builder.SQLBuilder;
    import org.codefilarete.stalactite.query.api.CriteriaChain;
    import org.codefilarete.stalactite.query.model.FluentQueries;
    import org.codefilarete.stalactite.query.model.Query;
    import org.codefilarete.stalactite.query.api.QueryProvider;
    import org.codefilarete.stalactite.query.model.Where;
    import org.codefilarete.stalactite.sql.ddl.structure.Column;
    import org.codefilarete.stalactite.sql.ddl.structure.Table;
    import org.codefilarete.stalactite.sql.result.Accumulator;
    import org.codefilarete.tool.function.SerializableTriFunction;
    import org.danekja.java.util.function.serializable.SerializableBiFunction;
    import org.danekja.java.util.function.serializable.SerializableFunction;
    import org.danekja.java.util.function.serializable.SerializableSupplier;

    /**
     * Contract to interact with a Database with some basic manner
     *
     * @author Guillaume Mary
     */
    public interface DatabaseCrudOperations {

    	/**
    	 * Creates a {@link ExecutableBeanPropertyKeyQueryMapper} from a {@link QueryProvider}, so it helps to build beans from a {@link Query}.
    	 * Should be chained with {@link QueryMapper} mapping methods and obviously with its {@link ExecutableQuery#execute(Accumulator)}
    	 *
    	 * @param queryProvider the query provider to give the {@link Query} execute to populate beans
    	 * @param beanType type of created beans, used for returned type marker
    	 * @param <C> type of created beans
    	 * @return a new {@link ExecutableBeanPropertyKeyQueryMapper} that must be configured and executed
    	 * @see FluentQueries
    	 */
    	<C> ExecutableBeanPropertyKeyQueryMapper<C> newQuery(QueryProvider<Query> queryProvider, Class<C> beanType);

    	/**
    	 * Creates a {@link ExecutableBeanPropertyKeyQueryMapper} from a {@link Query} in order to build beans from the {@link Query}.
    	 * Should be chained with {@link ExecutableBeanPropertyKeyQueryMapper} mapping methods and obviously with its {@link ExecutableQuery#execute(Accumulator)}
    	 *
    	 * @param query the query to execute to populate beans
    	 * @param beanType type of created beans, used for returned type marker
    	 * @param <C> type of created beans
    	 * @return a new {@link ExecutableBeanPropertyKeyQueryMapper} that must be configured and executed
    	 */
    	<C> ExecutableBeanPropertyKeyQueryMapper<C> newQuery(Query query, Class<C> beanType);

    	/**
    	 * Creates a {@link ExecutableBeanPropertyKeyQueryMapper} from some SQL in order to build beans from the SQL.
    	 * Should be chained with {@link ExecutableBeanPropertyKeyQueryMapper} mapping methods and obviously with its {@link ExecutableQuery#execute(Accumulator)}
    	 *
    	 * @param sql the SQL to execute to populate beans
    	 * @param beanType type of created beans, used for returned type marker
    	 * @param <C> type of created beans
    	 * @return a new {@link ExecutableBeanPropertyKeyQueryMapper} that must be configured and executed
    	 */
    	<C> ExecutableBeanPropertyKeyQueryMapper<C> newQuery(CharSequence sql, Class<C> beanType);

    	/**
    	 * Same as {@link #newQuery(CharSequence, Class)} with an {@link SQLBuilder} as argument to be more flexible : final SQL will be built just
    	 * before execution.
    	 *
    	 * @param sql the builder of SQL to be called for final SQL
    	 * @param beanType type of created beans, used for returned type marker
    	 * @param <C> type of created beans
    	 * @return a new {@link ExecutableBeanPropertyKeyQueryMapper} that must be configured and executed
    	 */
    	<C> ExecutableBeanPropertyKeyQueryMapper<C> newQuery(SQLBuilder sql, Class<C> beanType);

    	/**
    	 * Queries the database for given column and invokes given 1-arg constructor with it.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only column table is queried : no join nor assembly is made.
    	 * Prefer {@link #select(SerializableFunction, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a one-argument bean constructor
    	 * @param column any table column (primary key may be preferred because its result is given to bean constructor but it is not expected)
    	 * @param <C> type of created beans
    	 * @param <I> constructor arg and column types
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableFunction, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, T extends Table> List<C> select(SerializableFunction<I, C> factory, Column<T, I> column);

    	/**
    	 * Queries the database for given columns and invokes given 2-args constructor with them.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only columns table is queried : no join nor assembly are processed.
    	 * Prefer {@link #select(SerializableBiFunction, Column, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a two-arguments bean constructor
    	 * @param column1 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param column2 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param <C> type of created beans
    	 * @param <I> constructor first-arg type and first column type
    	 * @param <J> constructor second-arg type and second column type
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableBiFunction, Column, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, J, T extends Table> List<C> select(SerializableBiFunction<I, J, C> factory, Column<T, I> column1, Column<T, J> column2);

    	/**
    	 * Queries the database for given columns and invokes given 3-args constructor with them.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only columns table is queried : no join nor assembly are processed.
    	 * Prefer {@link #select(SerializableBiFunction, Column, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a two-arguments bean constructor
    	 * @param column1 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param column2 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param column3 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param <C> type of created beans
    	 * @param <I> constructor first-arg type and first column type
    	 * @param <J> constructor second-arg type and second column type
    	 * @param <K> constructor third-arg type and third column type
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableBiFunction, Column, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, J, K, T extends Table> List<C> select(SerializableTriFunction<I, J, K, C> factory, Column<T, I> column1, Column<T, J> column2, Column<T, K> column3);

    	/**
    	 * Queries the database and invokes given no-arg constructor for each row.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only columns table is queried : no join nor assembly are processed.
    	 * Prefer {@link #select(SerializableBiFunction, Column, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a two-arguments bean constructor
    	 * @param <C> type of created beans
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableBiFunction, Column, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, T extends Table> List<C> select(SerializableSupplier<C> factory, Consumer<SelectMapping<C, T>> selectMapping);

    	/**
    	 * Queries the database for given columns and invokes given 1-arg constructor with it.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only column table is queried : no join nor assembly are processed.
    	 * Prefer {@link #select(SerializableFunction, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a one-argument bean constructor
    	 * @param column any table column (primary key may be preferred because its result is given to bean constructor but it is not expected)
    	 * @param selectMapping allow to add some mapping beyond instantiation time
    	 * @param <C> type of created beans
    	 * @param <I> constructor arg and column types
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableFunction, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, T extends Table> List<C> select(SerializableFunction<I, C> factory, Column<T, I> column, Consumer<SelectMapping<C, T>> selectMapping);

    	/**
    	 * Queries the database for given columns and invokes given 2-args constructor with them.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases because IT DOESN'T FILTER DATABASE ROWS : no where clause is appended to the query.
    	 * Moreover, only columns table is queried : no join nor assembly are processed.
    	 * Prefer {@link #select(SerializableFunction, Column, Consumer, Consumer)} for a more complete use case, or even {@link #newQuery(SQLBuilder, Class)}
    	 *
    	 * @param factory a two-arguments bean constructor
    	 * @param column1 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param column2 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param selectMapping allow to add some mapping beyond instantiation time
    	 * @param <C> type of created beans
    	 * @param <I> constructor arg and column types
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableFunction, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, J, T extends Table> List<C> select(SerializableBiFunction<I, J, C> factory, Column<T, I> column1, Column<T, J> column2,
    											 Consumer<SelectMapping<C, T>> selectMapping);

    	/**
    	 * Queries the database and invokes given no-arg constructor for each row.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases : only columns table is targeted (no join nor assembly are processed).
    	 * Prefer {@link #newQuery(SQLBuilder, Class)} for a more complete use case.
    	 *
    	 * @param factory a two-arguments bean constructor
    	 * @param <C> type of created beans
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #select(SerializableBiFunction, Column, Column, Consumer, Consumer)
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, T extends Table> List<C> select(SerializableSupplier<C> factory, Consumer<SelectMapping<C, T>> selectMapping,
    									   Consumer<CriteriaChain> where);

    	/**
    	 * Queries the database for given column and invokes given 1-arg constructor with it.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases : only columns table is targeted (no join nor assembly are processed).
    	 * Prefer {@link #newQuery(SQLBuilder, Class)} for a more complete use case.
    	 *
    	 * @param factory a one-argument bean constructor
    	 * @param column any table column (primary key may be preferred because its result is given to bean constructor but it is not expected)
    	 * @param selectMapping allow to add some mapping beyond instantiation time
    	 * @param <C> type of created beans
    	 * @param <I> constructor arg and column types
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, T extends Table> List<C> select(SerializableFunction<I, C> factory, Column<T, I> column,
    										  Consumer<SelectMapping<C, T>> selectMapping,
    										  Consumer<CriteriaChain> where);

    	/**
    	 * Queries the database for given columns and invokes given 2-args constructor with them.
    	 * Additional bean fulfillment will be done by using configuration you'll give through {@link SelectMapping}.
    	 * <p>
    	 * Usage is for very simple cases : only columns table is targeted (no join nor assembly are processed).
    	 * Prefer {@link #newQuery(SQLBuilder, Class)} for a more complete use case.
    	 *
    	 * @param factory a one-argument bean constructor
    	 * @param column1 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param column2 a table column (may be a primary key column because its result is given to bean constructor but it is not expected)
    	 * @param selectMapping allow to add some mapping beyond instantiation time
    	 * @param <C> type of created beans
    	 * @param <I> constructor first-arg type and first column type
    	 * @param <J> constructor second-arg type and second column type
    	 * @param <T> targeted table type
    	 * @return a set of all table records mapped to the given bean
    	 * @see #newQuery(SQLBuilder, Class)
    	 */
    	<C, I, J, T extends Table> List<C> select(SerializableBiFunction<I, J, C> factory, Column<T, I> column1, Column<T, J> column2,
    											 Consumer<SelectMapping<C, T>> selectMapping,
    											 Consumer<CriteriaChain> where);

    	<T extends Table<T>> ExecutableInsert<T> insert(T table);

    	<T extends Table<T>> BatchInsert<T> batchInsert(T table);

    	default <T extends Table<T>> ExecutableUpdate<T> update(T table) {
    		return update(table, new Where());
    	}

    	<T extends Table<T>> ExecutableUpdate<T> update(T table, CriteriaChain<?> where);

    	default <T extends Table<T>> BatchUpdate<T> batchUpdate(T table) {
    		return batchUpdate(table, new Where());
    	}

    	default <T extends Table<T>> BatchUpdate<T> batchUpdate(T table, CriteriaChain<?> where) {
    		return batchUpdate(table, table.getColumns(), where);
    	}

    	default <T extends Table<T>> BatchUpdate<T> batchUpdate(T table, Set<? extends Column<T, ?>> columns) {
    		return batchUpdate(table, columns, new Where());
    	}

    	<T extends Table<T>> BatchUpdate<T> batchUpdate(T table, Set<? extends Column<T, ?>> columns, CriteriaChain<?> where);

    	default <T extends Table<T>> ExecutableDelete<T> delete(T table) {
    		return delete(table, new Where());
    	}

    	<T extends Table<T>> ExecutableDelete<T> delete(T table, CriteriaChain<?> where);

    	default <T extends Table<T>> BatchDelete<T> batchDelete(T table) {
    		return batchDelete(table, new Where());
    	}

    	<T extends Table<T>> BatchDelete<T> batchDelete(T table, CriteriaChain<?> where);
    }